package oneD.fem.method;

import inf.v3d.view.Viewer;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.StringTokenizer;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

import oneD.fem.visualize.TrussVisualizer;
import oneD.fem.visualize.Visualizer;


import ptolemy.plot.Plot;

public class Plot1D extends JFrame {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private JTextField nTf = new JTextField("100");
	private JTextField sTf = new JTextField("0.05");
	private JTextField psiTf = new JTextField("1.0");
	private JTextField nodeTf = new JTextField("0,1");
	private JCheckBox showGridCb = new JCheckBox("Show grid");
	private JCheckBox xCb = new JCheckBox("x");
	private JCheckBox yCb = new JCheckBox("y");
	private JCheckBox zCb = new JCheckBox("z");
	private Plot plot = new Plot();

	private ArcLengthControl controller_;

	public Plot1D(ArcLengthControl controller) {
		setTitle("Arc length load displacement control");
		setLayout(new BorderLayout(5, 5));

		add(createWestPanel(), BorderLayout.WEST);
		add(this.plot, BorderLayout.CENTER);
		add(createSouthPanel(), BorderLayout.SOUTH);

		Toolkit tk = Toolkit.getDefaultToolkit();
		int xSize = ((int) tk.getScreenSize().getWidth());
		int ySize = ((int) tk.getScreenSize().getHeight());
		setSize(xSize - 100, ySize);

		this.controller_ = controller;

		nTf.setText(Integer.toString(controller_.getNumStep()));
		psiTf.setText(Double.toString(controller_.getPsi()));
		sTf.setText(Double.toString(controller_.getParameterS()));
		
		xCb.setSelected(true);
		yCb.setSelected(true);
		showGridCb.setSelected(true);
	}

	private JPanel createWestPanel() {
		JPanel wp = new JPanel(new BorderLayout());
		wp.add(createSettingsPanel(), BorderLayout.NORTH);
		wp.add(createDisplayPanel(), BorderLayout.AFTER_LAST_LINE);
		
		return wp;
	}

	private JPanel createSettingsPanel() {
		JPanel sp = new JPanel(new BorderLayout(5, 5));
		JPanel p1 = new JPanel(new GridLayout(3, 1, 0, 2));
		JPanel p2 = new JPanel(new GridLayout(3, 1, 0, 2));
		JPanel p3 = new JPanel(new GridLayout(1, 1, 0, 2));

		p1.add(new JLabel("n = ", JLabel.RIGHT));
		p1.add(new JLabel("s = ", JLabel.RIGHT));
		p1.add(new JLabel("psi = ", JLabel.RIGHT));

		p2.add(this.nTf);
		p2.add(this.sTf);
		p2.add(this.psiTf);
		
		p3.add(createRunButton());

		sp.setBorder(BorderFactory.createTitledBorder("Settings"));
		sp.add(p1, BorderLayout.WEST);
		sp.add(p2, BorderLayout.CENTER);
		sp.add(p3, BorderLayout.SOUTH);

		return sp;
	}
	private JPanel createDisplayPanel() {
		JPanel sp = new JPanel(new BorderLayout(5, 5));
		JPanel p1 = new JPanel(new GridLayout(1, 1, 0, 2));
		JPanel p2 = new JPanel(new GridLayout(1, 1, 0, 2));
		JPanel p3 = new JPanel(new GridLayout(6, 1, 0, 2));
		
		p1.add(new JLabel("node:", JLabel.RIGHT));
		
		p2.add(this.nodeTf);
		
		p3.add(this.xCb);
		p3.add(this.yCb);
		p3.add(this.zCb);
		p3.add(this.showGridCb);
		p3.add(createPlotButton());
		p3.add(createVisualizeButton());
		
		sp.setBorder(BorderFactory.createTitledBorder("Display"));
		sp.add(p1, BorderLayout.WEST);
		sp.add(p2, BorderLayout.CENTER);
		sp.add(p3, BorderLayout.SOUTH);
		
		return sp;
	}

	private JPanel createSouthPanel() {
		JPanel p = new JPanel(new FlowLayout(FlowLayout.RIGHT));
//		p.add(createRunButton());
//		p.add(createPlotButton());
		p.add(createExitButton());
		return p;
	}

	private JButton createExitButton() {
		JButton b = new JButton("Exit");

		b.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}
		});
		return b;
	}

	private JButton createPlotButton() {
		JButton b = new JButton("Plot");

		b.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				plot();
			}
		});
		return b;
	}
	
	private JButton createVisualizeButton() {
		JButton b = new JButton("Visualize");
		
		b.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				Viewer view = new Viewer();
				Visualizer viz = new TrussVisualizer(controller_.getStructure(), view);
				viz.automaticScale();
				viz.drawElements();
				viz.drawConstraints();
				viz.drawForces();
			}
		});
		return b;
	}

	private JButton createRunButton() {
		JButton b = new JButton("Run");

		b.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				controller_.clear();
				controller_.setNumStep(Integer.parseInt(nTf.getText()));
				controller_.setParameterS(Double.parseDouble(sTf.getText()));
				controller_.setPsi(Double.parseDouble(psiTf.getText()));
				controller_.run();
			}
		});
		return b;
	}

	private void plot() {
		try {
			this.plot.clear(true);
			this.plot.setGrid(this.showGridCb.isSelected());
			this.plot.setXLabel("load");
			this.plot.setYLabel("displacement");

			Integer[] nodeIdSet = this.getNodeIdSet();
			Integer[] axisSet = this.getAxisSet();

			for (int i = 0; i < nodeIdSet.length; i++)
				for (int k = 0; k < axisSet.length; k++) {
					int datasetId = i * axisSet.length + k;
					String legend = "u" + i + getAxisName(axisSet[k]);
					this.plot.addLegend(datasetId, legend);
					for (int l = 0; l < controller_.getNumStep(); l++) {
						double x = controller_.getLoad(l);
						double y = controller_.getDisplacement(l, nodeIdSet[i])
								.get(axisSet[k]);
						this.plot.addPoint(datasetId, x, y, true);
					}
				}

			this.plot.repaint();
		} catch (Exception e) {
			JOptionPane.showMessageDialog(this, e.getMessage());
		}
	}

	private Integer[] getAxisSet() {
		ArrayList<Integer> list = new ArrayList<Integer>();
		if (this.xCb.isSelected())
			list.add(0);
		if (this.yCb.isSelected())
			list.add(1);
		if (this.zCb.isSelected())
			list.add(2);
		Integer[] a = list.toArray(new Integer[list.size()]);
		return a;
	}

	private Integer[] getNodeIdSet() {
		ArrayList<Integer> list = new ArrayList<Integer>();
		String s = this.nodeTf.getText();
		StringTokenizer st = new StringTokenizer(s, ",");
		while (st.hasMoreTokens()) {
			String val = st.nextToken();
			list.add(Integer.parseInt(val));
		}
		Integer[] a = list.toArray(new Integer[list.size()]);
		return a;
	}

	private String getAxisName(int axisNumber) {
		return axisNumber == 0 ? "x" : axisNumber == 1 ? "y" : "z";
	}

}
